/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2024.
 * Description: rtos printk feature
 * Author: Wang Haitao
 * Create: 2023/9/13
 */

#ifdef CONFIG_RTOS_EARLY_KBOX
DEFINE_SEMAPHORE(nolevel_console_sem);
struct console *nolevel_console_drivers;
u64 ekbox_console_start_seq = ULLONG_MAX;
u64 ekbox_console_end_seq;

/* add a console to nolevel_console_drivers */
void register_nolevel_console(struct console *newcon)
{
	BUG_ON(in_interrupt());
	down(&nolevel_console_sem);
	nolevel_console_drivers = newcon;
	up(&nolevel_console_sem);
}

void call_nolevel_console_drivers(const char *text, size_t len)
{
/*
 * nolevel_console_drivers may change as NULL during copying work,
 * we define con to keep the pointer
 */
	struct console *con = nolevel_console_drivers;

	if (con && (con->flags & CON_ENABLED) && con->write &&
		(cpu_online(smp_processor_id()) || (con->flags & CON_ANYTIME)))
		con->write(con, text, len);
}

static inline void update_ekbox_max_min_seq(u64 max, u64 min)
{
	ekbox_console_start_seq = (ekbox_console_start_seq > min) ? (min) : (ekbox_console_start_seq);
	ekbox_console_end_seq = (ekbox_console_end_seq < max) ? (max) : (ekbox_console_end_seq);
}

bool write_ekbox_console(struct printk_record *r, u64 *tmp_min, u64 *tmp_max,
				char *text, size_t len)
{
	if (nolevel_console_drivers) {
		/*
		* no more recording between start and end to prevent duplication
		*/
		if (console_seq > ekbox_console_end_seq || console_seq < ekbox_console_start_seq) {
			*tmp_min = (console_seq < *tmp_min) ? (console_seq) : (*tmp_min);
			*tmp_max = (console_seq > *tmp_max) ? (console_seq) : (*tmp_max);
			call_nolevel_console_drivers(text, len);
		}

		if (suppress_message_printing(r->info->level)) {
			console_seq++;
			return true;
		}
	}
	return false;
}

inline bool has_console_drivers(void)
{
	return nolevel_console_drivers != NULL;
}
 
#else
inline bool has_console_drivers(void)
{
	return false;
}
#endif // end of CONFIG_RTOS_EARLY_KBOX
